//
// Copyright (C) [2024] Xingyun Integrated Circuit, Inc.
//
// GreenCode was a private technology asset of Xingyun Integrated Circuit， Inc （Confidential）
//  Author: Shawn.Tan
//  Date : 2025.10.28
//
//  History : Initial Version 2025.10.28
//

//
#include "RegisterReserverGPGPU.h"

#include "Constraint.h"
#include "ConstraintGPGPU.h"
#include "Log.h"
#include "Register.h"

using namespace std;

/*
  \file RegisterReserverGPGPU.cc
  \brief Code supporting providing RISC-specific functionality for reserving registers.
*/

namespace Green
{

  RegisterReserverGPGPU::RegisterReserverGPGPU()
    : RegisterReserver(), mReserveGroupsByOprType(), mReserveGroupsByRegType()
  {
    mReserveGroupsByOprType.emplace(EOperandType::GPR, ERegReserveGroup::GPR);
    mReserveGroupsByOprType.emplace(EOperandType::Register, ERegReserveGroup::GPR);
    mReserveGroupsByOprType.emplace(EOperandType::FPR, ERegReserveGroup::FPRSIMDR);
    mReserveGroupsByOprType.emplace(EOperandType::VECREG, ERegReserveGroup::VECREG);
    mReserveGroupsByOprType.emplace(EOperandType::SysReg, ERegReserveGroup::SystemRegister);
    mReserveGroupsByOprType.emplace(EOperandType::UGPR, ERegReserveGroup::UGPR);
    mReserveGroupsByOprType.emplace(EOperandType::PR, ERegReserveGroup::PredicateRegister);
    mReserveGroupsByOprType.emplace(EOperandType::UP, ERegReserveGroup::UnifiedPredicateRegister);
    mReserveGroupsByOprType.emplace(EOperandType::BR, ERegReserveGroup::BranchRegister);

    mReserveGroupsByRegType.emplace(
      ERegisterType::GPR,
      vector<ERegReserveGroup>({ERegReserveGroup::GPR}));
    mReserveGroupsByRegType.emplace(
      ERegisterType::ZR,
      vector<ERegReserveGroup>({ERegReserveGroup::GPR}));
    mReserveGroupsByRegType.emplace(
      ERegisterType::FPR,
      vector<ERegReserveGroup>({ERegReserveGroup::FPRSIMDR}));
    mReserveGroupsByRegType.emplace(
      ERegisterType::SIMDR,
      vector<ERegReserveGroup>({ERegReserveGroup::FPRSIMDR}));
    mReserveGroupsByRegType.emplace(
      ERegisterType::VECREG,
      vector<ERegReserveGroup>({ERegReserveGroup::VECREG}));
    mReserveGroupsByRegType.emplace(
      ERegisterType::SysReg,
      vector<ERegReserveGroup>({ERegReserveGroup::SystemRegister}));
    mReserveGroupsByRegType.emplace(
      ERegisterType::PR,
      vector<ERegReserveGroup>({ERegReserveGroup::PredicateRegister}));
    mReserveGroupsByRegType.emplace(
      ERegisterType::UP,
      vector<ERegReserveGroup>({ERegReserveGroup::UnifiedPredicateRegister}));
    mReserveGroupsByRegType.emplace(
      ERegisterType::UR,
      vector<ERegReserveGroup>({ERegReserveGroup::UGPR}));
    mReserveGroupsByRegType.emplace(
      ERegisterType::BR,
      vector<ERegReserveGroup>({ERegReserveGroup::BranchRegister}));
  }

  RegisterReserverGPGPU::RegisterReserverGPGPU(const RegisterReserverGPGPU& rOther)
    : RegisterReserver(rOther), mReserveGroupsByOprType(rOther.mReserveGroupsByOprType), mReserveGroupsByRegType(rOther.mReserveGroupsByRegType)
  {
  }

  ERegReserveGroup RegisterReserverGPGPU::GetReserveGroupForOperandType(const EOperandType oprType) const
  {
    auto itr = mReserveGroupsByOprType.find(oprType);
    if (itr == mReserveGroupsByOprType.end()) {
      LOG(fail) << "{RegisterReserverGPGPU::GetReserveGroupForOperandType} unsupported operand type: " << EOperandType_to_string(oprType) << endl;
      FAIL("unsupported-operand-type");
    }

    return itr->second;
  }

  const vector<ERegReserveGroup>& RegisterReserverGPGPU::GetReserveGroupsForRegisterType(const ERegisterType regType) const
  {
    auto itr = mReserveGroupsByRegType.find(regType);
    if (itr == mReserveGroupsByRegType.end()) {
      LOG(fail) << "{RegisterReserverGPGPU::GetReserveGroupForRegisterType} unsupported register type: " << ERegisterType_to_string(regType) << endl;
      FAIL("unsupported-register-type");
    }

    return itr->second;
  }

  void RegisterReserverGPGPU::GetRegisterIndexRange(const ERegisterType regType, ConstraintSet* pIndexConstr) const
  {
    ConstraintSetGPGPU* pIndexConstrGPGPU = static_cast<ConstraintSetGPGPU*>(pIndexConstr);
    switch (regType) {

    case ERegisterType::GPR:
      pIndexConstr->AddRange(0, GetUpperLimit(ERegisterType::GPR, pIndexConstrGPGPU->GetWarpLimit()));
      break;
    case ERegisterType::UP:
      pIndexConstr->AddRange(0, GetUpperLimit(ERegisterType::UP, pIndexConstrGPGPU->GetWarpLimit()));
      break;
    case ERegisterType::PR:
      pIndexConstr->AddRange(0, GetUpperLimit(ERegisterType::PR, pIndexConstrGPGPU->GetWarpLimit()));
      break;
    case ERegisterType::UR:
      pIndexConstr->AddRange(0, GetUpperLimit(ERegisterType::UR, pIndexConstrGPGPU->GetWarpLimit()));
      break;
    case ERegisterType::BR:
      pIndexConstr->AddRange(0, GetUpperLimit(ERegisterType::BR, pIndexConstrGPGPU->GetWarpLimit()));
      break;
    default:
      LOG(fail) << "{RegisterReserverGPGPU::GetRegisterIndexRange} unsupported register type: " << ERegisterType_to_string(regType) << endl;
      FAIL("unsupported-register-type");
    }
  }

  uint32 RegisterReserverGPGPU::GetPhysicalRegisterIndex(const PhysicalRegister* pPhysReg, const ERegisterType regType) const
  {
    uint32 reg_index = pPhysReg->IndexValue();

    return reg_index;
  }

  uint64 RegisterReserverGPGPU::GetUpperLimit(const ERegisterType regType, const uint32_t  &limit) const
  {
    uint64 result = 0;
    switch (regType) {

    case ERegisterType::GPR:
      result = (limit > 8) ? 31 : (limit > 4) ?  63 : (limit > 2) ? 127 : 255; 
      break;
    case ERegisterType::UP:
      result =  (limit > 8) ? 7 : (limit > 4) ?  15 : (limit > 2) ? 31 : 63;
      break;
    case ERegisterType::PR:
      result =  (limit > 8) ? 7 : (limit > 4) ?  15 : (limit > 2) ? 31 : 63;
      break;
    case ERegisterType::UR:
      result =  (limit > 8) ? 63 : (limit > 4) ?  127 : (limit > 2) ? 255 : 511;
      break;
    case ERegisterType::BR:
      result =  15;
      break;
    default:
      LOG(fail) << "{RegisterReserverGPGPU::GetUpperLimit} unsupported register type: " << ERegisterType_to_string(regType) << endl;
      FAIL("unsupported-register-type");
    }

    if (!result) {
      LOG(fail) << "{RegisterReserverGPGPU::GetUpperLimit} can't get valid register index range : " << endl;
      FAIL("invalid-register-index");
    }

    return result;
  }

}
